﻿using Avalonia.Data;
using Avalonia.Styling;
using GraphShape.Algorithms.Layout;
using GraphShape.Algorithms.Layout.Contextual;
using QuikGraph;

namespace GraphShape.Controls
{
    public class ContextualGraphLayoutProperties : AvaloniaObject
    {
    }
    
    
    /// <summary>
    /// Contextual Graph layout control.
    /// </summary>
    /// <typeparam name="TVertex">Vertex type.</typeparam>
    /// <typeparam name="TEdge">Edge type.</typeparam>
    /// <typeparam name="TGraph">Graph type.</typeparam>
    public class ContextualGraphLayout<TVertex, TEdge, TGraph> : GraphLayout<TVertex, TEdge, TGraph>
        where TVertex : class
        where TEdge : IEdge<TVertex>
        where TGraph : class, IBidirectionalGraph<TVertex, TEdge>
    {
        static ContextualGraphLayout()
        {
            var t = typeof(ContextualGraphLayout<TVertex, TEdge, TGraph>);
            LayoutAlgorithmFactoryProperty.OverrideMetadata(
                                                            t,
                                                            new StyledPropertyMetadata<ILayoutAlgorithmFactory<TVertex, TEdge, TGraph>>(
                                                                                                                                        new ContextualLayoutAlgorithmFactory<TVertex, TEdge, TGraph>(),
                                                                                                                                        BindingMode.OneWay,
                                                                                                                                        CoerceLayoutAlgorithmFactory));

            SelectedVertexProperty.Changed.Subscribe(OnSelectedVertexPropertyChanged);
        }

        #region SelectedVertex

        /// <summary>
        /// Gets or sets the <see cref="SelectedVertex"/> which influences the context.
        /// </summary>
        public TVertex SelectedVertex
        {
            get => GetValue(SelectedVertexProperty);
            set => SetValue(SelectedVertexProperty, value);
        }

        /// <summary>
        /// Selected vertex dependency property.
        /// </summary>
        [NotNull]
        public static readonly StyledProperty<TVertex> SelectedVertexProperty
            = AvaloniaProperty.Register<ContextualGraphLayoutProperties, TVertex>(nameof(SelectedVertex));

        private static void OnSelectedVertexPropertyChanged(AvaloniaPropertyChangedEventArgs<TVertex> args)
        {
            var graphLayout = args.Sender as ContextualGraphLayout<TVertex, TEdge, TGraph>;

            // Refresh the layout on context change
            graphLayout?.Relayout();
        }

        #endregion

        /// <inheritdoc />
        protected override ILayoutContext<TVertex, TEdge, TGraph> CreateLayoutContext(
            IDictionary<TVertex, gPoint> positions,
            IDictionary<TVertex, Size> sizes)
        {
            return new ContextualLayoutContext<TVertex, TEdge, TGraph>(Graph, SelectedVertex, positions, sizes);
        }

        /// <inheritdoc />
        protected override bool CanLayout => SelectedVertex != null && base.CanLayout;
    }
}